package project2.server;

import project2.client.GreetingService;
import project2.shared.FieldVerifier;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
		GreetingService
{
	/** The previous word read from the text area. */
	private String previousWord = "";

	/** The word currently being read from the text area. */
	private String currentWord = "";

	/** True if the last character was a delimiter. */
	private boolean isLastDelimiter = true;



	public String greetServer(String input) throws IllegalArgumentException
	{
		String duplicates = "";

		// Verify that the input is valid.
		if (!FieldVerifier.isValidText(input)) {
			// If the input is not valid, throw an IllegalArgumentException back
			// to the client.
			throw new IllegalArgumentException(
					"Text must be at least 10 characters long");
		}

		// Escape data from the client to avoid cross-site script
		// vulnerabilities.
		input = escapeHtml(input);

		duplicates = determineStutter(input);

		if (duplicates.equals(""))
			return "No repeated words were found";
		else
			return duplicates;
	}



	/**
	 * Reads the lines from the text area. The characters in the text area is
	 * passed from the client to the server as text, so the string is split into
	 * an array of {@code String}s based on the new line character. The
	 * characters in each line is then compared to the delimiters[] array to
	 * determine if it is a delimiter, signaling the end of a word. When the end
	 * of a word is reached, {@code checkDuplicates()} is called to determine if
	 * it is the same as the {@code previousWord}.
	 * 
	 * @param text the text to be checked for duplicated words.
	 * @return a string stating where the duplicated words were found.
	 */
	private String determineStutter(String text)
	{
		int lineNo = 1;
		String duplicatedWords = "";
		String thisLine = null;
		String[] lines = null;
		char c;

		lines = text.split("\n");

		for (int l = 0; l < lines.length; l++) {
			thisLine = lines[l];

			for (int i = 0; i < thisLine.length(); i++) {
				c = thisLine.charAt(i);

				if (isDelimiter(c))
					duplicatedWords += checkDuplicate(lineNo);
				else {
					isLastDelimiter = false;
					currentWord += c;
				}
			}
			duplicatedWords += checkDuplicate(lineNo);
			lineNo++;
		}

		return duplicatedWords;
	}



	/**
	 * Checks to see if a character is a delimiter. It compares the parameter
	 * against the delimiters[] array. If it is found in the array, then the
	 * character is a delimiter.
	 * 
	 * @param c the character to be compared.
	 * @return true, if the character is in the array and false otherwise.
	 */
	private boolean isDelimiter(char c)
	{
		char[] delimiters = { '\n', '	', ' ', ',', '.', '!', '-', '+', '=',
				';', ':', '?', '&', '{', '}', '\\' };

		for (int i = 0; i < delimiters.length; i++)
			if (c == delimiters[i])
				return true;

		return false;
	}



	/**
	 * Determines if there is a duplicate word. Checks if {@code currentWord} is
	 * the same as as the {@code previousWord} and prints a message if it is.
	 * 
	 * @param line the current line number.
	 * @return a partial string stating where the duplicated words are or an
	 *         empty string if no duplicates found.
	 */
	private String checkDuplicate(int line)
	{
		String duplicatedWords = "";
		if (!isLastDelimiter) {
			isLastDelimiter = true;

			if (currentWord.equalsIgnoreCase(previousWord))
				duplicatedWords = "Repeated word at line number  " + line +
						": " + previousWord + "<br>";
			else
				previousWord = currentWord;

			currentWord = "";
		}

		return duplicatedWords;
	}



	/**
	 * Escape an html string. Escaping data received from the client helps to
	 * prevent cross-site script vulnerabilities.
	 * 
	 * @param html the html string to escape
	 * @return the escaped string
	 */
	private String escapeHtml(String html)
	{
		if (html == null) {
			return null;
		}
		return html.replaceAll("&", "&amp;").replaceAll("<", "&lt;")
				.replaceAll(">", "&gt;");
	}
}
